// Author: wsfuyibing <682805@qq.com>
// Date: 2025-05-09

package encryption

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"server/app/config"
	"server/app/errs"
	"strconv"
	"strings"
	"time"
)

type (
	Manager interface {
		Decode(enc Encryption) (str string, err error)
		DecodeQrcode(enc Encryption) (id int64, sign string, err error)
		Encode(str string) (enc Encryption, err error)
		EncodeQrcode(id int64, sign string) (enc Encryption)
	}

	manager struct {
	}
)

func New() Manager {
	return &manager{}
}

// Decode
// 私钥解密.
func (o *manager) Decode(enc Encryption) (str string, err error) {
	var (
		body []byte
		key  *rsa.PrivateKey
	)
	if key, err = config.Encryption.GetPrivateKey(); err == nil {

		// key.Decrypt(rand.Reader, key, enc.Bytes(), nil)

		if body, err = rsa.DecryptOAEP(sha256.New(), rand.Reader, key, enc.Bytes(), nil); err == nil {
			str = string(body)
		}

		// if body, err = rsa.DecryptPKCS1v15(rand.Reader, key, enc.Bytes()); err == nil {
		//     str = string(body)
		// }
	}
	return
}

func (o *manager) DecodeQrcode(enc Encryption) (id int64, sign string, err error) {
	var split = strings.Split(enc.String(), ":")

	if len(split) != 3 {
		err = errs.ErrQrcodeNotFormatted
		return
	} else {
		sign = split[1]
	}

	if id, err = strconv.ParseInt(split[0], 10, 64); err != nil || id < 1 {
		err = errs.ErrQrcodeNotFormatted
	}
	return
}

// Encode
// 公钥加密.
func (o *manager) Encode(str string) (enc Encryption, err error) {
	var body []byte
	var key *rsa.PublicKey
	if key, err = config.Encryption.GetPublicKey(); err == nil {
		if body, err = rsa.EncryptOAEP(sha256.New(), rand.Reader, key, []byte(str), nil); err == nil {
			enc = Encryption(hex.EncodeToString(body))
		}
		// if body, err = rsa.En(rand.Reader, key, []byte(str)); err == nil {
		//     enc = Encryption(hex.EncodeToString(body))
		// }
	}
	return
}

// EncodeQrcode
// 二维码加密.
//
// 将原文字符串, 加密成用于生成二维码的字符串
func (o *manager) EncodeQrcode(id int64, sign string) (enc Encryption) {
	return Encryption(fmt.Sprintf(`%d:%s:%d`, id, sign, time.Now().Unix()))
}
